package ac.svn.accesscontrol.manager;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import ac.svn.accesscontrol.store.AccessUnit;
import ac.svn.accesscontrol.store.ISVNItem;
import ac.svn.accesscontrol.store.SVNGroup;
import ac.svn.accesscontrol.store.SVNLocation;
import ac.svn.accesscontrol.store.SVNTag;
import ac.svn.accesscontrol.store.SVNUser;

public class SVNInfoManager 
{
	private static  SVNInfoManager _infoManager = new SVNInfoManager();

	private Map<String,SVNUser> usersMap;
	private Map<String,SVNGroup> groupsMap;
	private Map<String, SVNLocation> locationsMap;
	private Map<String,SVNTag> tagsMap;
	private Map<String,AccessUnit> accessUnitsMap;

	/** 
	 * 	Method returns a newly created instance of svn information manager. Data will be copied into new instance depending 
	 * upon argument value. True value lead to copy of existing values and false return a blank instance.
	 * */
	public static SVNInfoManager getNewSvnInfoManager(boolean copyCurrentDatas)
	{
		SVNInfoManager infoManager = new SVNInfoManager();
		//Copy user data.
		for(String userId:getInfoManager().usersMap.keySet())
		{
			infoManager.updateUser(getInfoManager().usersMap.get(userId));
		}

		for(String groupId:getInfoManager().groupsMap.keySet())
		{
			infoManager.updateGroup(getInfoManager().groupsMap.get(groupId));
		}

		for(String locationId:getInfoManager().locationsMap.keySet())
		{
			infoManager.updateLocation(getInfoManager().locationsMap.get(locationId));
		}

		for(String tagId:getInfoManager().tagsMap.keySet() )
		{
			infoManager.tagsMap.put(tagId, getInfoManager().tagsMap.get(tagId));
		}

		for(AccessUnit accessUnit:getInfoManager().accessUnitsMap.values())
		{
			infoManager.accessUnitsMap.put(accessUnit.getAccessUnitId(), accessUnit);
		}
		return infoManager;
	}

	private SVNInfoManager()
	{
		this.usersMap   	= new HashMap<String, SVNUser>();
		this.groupsMap 		= new HashMap<String, SVNGroup>();
		this.locationsMap	= new HashMap<String, SVNLocation>();
		this.accessUnitsMap 	= new  HashMap<String, AccessUnit>();
	}

	public static SVNInfoManager getInfoManager() {
		return _infoManager;
	}

	public static void setInfoManager(SVNInfoManager infoManager) {
		SVNInfoManager._infoManager = infoManager;
	}

	public void updateUser(SVNUser svnUser )
	{
		_infoManager.usersMap.put(svnUser.getUserAlias(), svnUser);
	}


	public void updateGroup(SVNGroup svnGroup)
	{
		_infoManager.groupsMap.put(svnGroup.getGroupAlias(), svnGroup);
	}

	public void updateLocation(SVNLocation svnLocation)
	{
		_infoManager.locationsMap.put(svnLocation.getLocationPath(), svnLocation);
	}

	public void removeGroup(String groupAlias)
	{
		_infoManager.groupsMap.remove(groupAlias);
	}

	public void removeUser(String userAlias)
	{
		_infoManager.usersMap.remove(userAlias);
	}

	public void removeLocation(String locationPath)
	{
		_infoManager.locationsMap.remove(locationPath);
	}

	public Set<ISVNItem> getAllAccessUnit(String ownerId)
	{
		boolean criteriaEnabled = false;
		if((null != ownerId)&&(false == ownerId.isEmpty()))
		{
			criteriaEnabled = true;
		}

		//Get a new list for all access Unit.
		Set<ISVNItem> allAccessUnits = new HashSet<ISVNItem>();
		synchronized (accessUnitsMap) 
		{
			for(AccessUnit accessUnit: _infoManager.accessUnitsMap.values())
			{
				//If criteria is enabled on add access unit those matches the criteria.
				if(true == criteriaEnabled)
				{
					if(accessUnit.getOwnerId().equalsIgnoreCase(ownerId))
					{
						allAccessUnits.add(accessUnit);
					}
				}
				else
				{
					allAccessUnits.add(accessUnit);
				}
			}
		}
		return allAccessUnits;
	}

	public Set<ISVNItem> getAllGroups()
	{
		Set<ISVNItem> allGroups = new TreeSet<ISVNItem>();
		synchronized (groupsMap) {
			for(SVNGroup svnGroup: _infoManager.groupsMap.values())
			{
				allGroups.add(svnGroup);
			}
		}
		return allGroups;
	}

	public Set<ISVNItem> getAllUsers()
	{
		Set<ISVNItem> allUsers = new TreeSet<ISVNItem>();
		synchronized (usersMap) {
			for(SVNUser svnUser:_infoManager.usersMap.values())
			{
				allUsers.add(svnUser);
			}
		}
		return allUsers; 
	}

	public Set<ISVNItem> getAllLocations()
	{
		Set<ISVNItem> allLocations = new TreeSet<ISVNItem>();
		synchronized (locationsMap) {
			for(SVNLocation svnLocation:_infoManager.locationsMap.values())
			{
				allLocations.add(svnLocation);
			}
		}
		return allLocations;
	}

	public void addTag(SVNTag svnTag)
	{
		_infoManager.tagsMap.put(svnTag.getTagId(), svnTag);
	}

	public SVNTag getTag(String tagId)
	{
		return _infoManager.tagsMap.get(tagId);
	}

	public SVNGroup getGroup(String groupAlias)
	{
		return _infoManager.groupsMap.get(groupAlias);
	}

	public SVNLocation getLocation(String locationPath)
	{
		return _infoManager.locationsMap.get(locationPath);
	}

	public SVNUser getSvnUser(String userAlias)
	{
		return _infoManager.usersMap.get(userAlias);
	}

	public Set<ISVNItem> getUsersGroup(String userId)
	{
		Set<ISVNItem> usersGroup = new HashSet<ISVNItem>();
		SVNUser svnUser = getInfoManager().usersMap.get(userId);
		if(null != svnUser)
		{
			for(String groupId: svnUser.getGroups())
			{
				SVNGroup group = getInfoManager().getGroup(groupId);
				usersGroup.add(group);
			}
		}
		return usersGroup;
	}

	public boolean isAGroup(String id)
	{
		for(String grpId:getInfoManager().groupsMap.keySet())
		{
			if(grpId.trim().equalsIgnoreCase(id.trim()))
			{
				return true;
			}
		}
		return false;
	}

	public void clearAll()
	{
		getInfoManager().groupsMap.clear();
		getInfoManager().usersMap.clear();
		getInfoManager().locationsMap.clear();
	}

	public void updateAccessUnit(AccessUnit accessUnit)
	{
		if(null != accessUnit)
		{
			getInfoManager().accessUnitsMap.put(accessUnit.getId(), accessUnit);
		}
	}

	public AccessUnit getAccessUnit(String accessUnitId)
	{
		return getInfoManager().accessUnitsMap.get(accessUnitId);
	}

	public ISVNItem getAccessUnit(String ownerId,String locationId)
	{
		ISVNItem accessU = null;		
		//Get User details
		SVNUser svnUser = getInfoManager().getSvnUser(ownerId);
		//Get Location details.
		synchronized (locationsMap) {
			SVNLocation svnLoc = getInfoManager().getLocation(locationId);
			//Check both are present
			if((null != svnUser) && (null != svnLoc))
			{
				//Get all groups of user.
				//Set<String> usersGroup = svnUser.getGroups();
				//Check in all access unit if any ownerIsd matches with assigned groups
				for(String accessUnitId : svnLoc.getAccessUnits())
				{
					AccessUnit  accessUnit = getInfoManager().getAccessUnit(accessUnitId);
					if(//usersGroup.contains(accessUnit.getOwnerId())||
							ownerId.equalsIgnoreCase(accessUnit.getOwnerId()))
					{
						accessU = accessUnit;
						break;
					}
				}
			}
		}

		return accessU;		
	}

	public ISVNItem getAccessUnitViaGroup(String ownerId,String locationId)
	{
		ISVNItem accessU = null;		
		//Get User details
		SVNUser svnUser = getInfoManager().getSvnUser(ownerId);
		//Get Location details.
		SVNLocation svnLoc = getInfoManager().getLocation(locationId);
		//Check both are present
		if((null != svnUser) && (null != svnLoc))
		{
			//Get all groups of user.
			Set<String> usersGroup = svnUser.getGroups();
			//Check in all access unit if any ownerIsd matches with assigned groups
			for(String accessUnitId : svnLoc.getAccessUnits())
			{
				AccessUnit  accessUnit = getInfoManager().getAccessUnit(accessUnitId);
				if(usersGroup.contains(accessUnit.getOwnerId()))
				{
					accessU = accessUnit;
					break;
				}
			}
		}
		return accessU;		
	}


	/**
	 *	Method check whether mentioned location is accessible to user through a group or not.  
	 */
	public boolean isLocationAccessibleThroughGroup(String userId,String locationId)
	{
		boolean byGroup = false;
		boolean byUser     = false;
		//Get User details
		SVNUser svnUser = getInfoManager().getSvnUser(userId);
		//Get Location details.
		SVNLocation svnLoc = getInfoManager().getLocation(locationId);
		//Check both are present
		if((null != svnUser) && (null != svnLoc))
		{
			for(String accessUnitId : svnLoc.getAccessUnits())
			{
				AccessUnit  accessUnit = getInfoManager().getAccessUnit(accessUnitId);
				if(userId.contains(accessUnit.getOwnerId()))
				{
					byUser = true;
					break;
				}
			}
			if(false == byUser )
			{
				//Get all groups of user.
				Set<String> usersGroup = svnUser.getGroups();
				//Check in all access unit if any ownerid matches with assigned groups
				for(String accessUnitId : svnLoc.getAccessUnits())
				{
					AccessUnit  accessUnit = getInfoManager().getAccessUnit(accessUnitId);
					if(usersGroup.contains(accessUnit.getOwnerId()))
					{
						byGroup = true; 
						break;
					}
				}
			}
		}
		return  byGroup;
	}

	public void removeAccessUnit(String accessUnitId)
	{
		//Remove reference of access unit from all locations.
		for(ISVNItem location: getInfoManager().getAllLocations())
		{
			SVNLocation svnLocation = (SVNLocation) location;
			if(svnLocation.getAccessUnits().contains(accessUnitId))
			{
				svnLocation.getAccessUnits().remove(accessUnitId);
				getInfoManager().updateLocation(svnLocation);
			}
		}

		//Remove main location of access unit
		getInfoManager().accessUnitsMap.remove(accessUnitId);

	}

	public boolean isExistingGroup(String groupName)
	{
		if(null != groupName)
		{
			boolean groupPresent = false;
			for(ISVNItem group : getInfoManager().getAllGroups())
			{
				SVNGroup svnGroup = (SVNGroup) group;
				if(groupName.equalsIgnoreCase(svnGroup.getGroupName())
						|| groupName.equalsIgnoreCase(svnGroup.getGroupAlias()))
				{
					groupPresent = true;
					break;
				}
			}
			return groupPresent;
		}
		else
		{
			return false;
		}
	}


	public boolean isLocationWithNameExists(final String locationName)
	{
		boolean checkResult = false;
		if(null != locationName)
		{
			for(ISVNItem location : getInfoManager().getAllLocations())
			{
				SVNLocation svnLocation = (SVNLocation) location;
				if(true == locationName.equalsIgnoreCase(svnLocation.getLocationName()))
				{
					checkResult = true;
					break;
				}
			}	    
		}

		return checkResult;
	}

	public boolean isLocationWithPathExists(final String locationPath)
	{
		boolean checkResult = false;
		if(null != locationPath)
		{
			for(ISVNItem location : getInfoManager().getAllLocations())
			{
				SVNLocation svnLocation = (SVNLocation) location;
				if(true == locationPath.equalsIgnoreCase(svnLocation.getLocationPath()))
				{
					checkResult = true;
					break;
				}
			}	    
		}

		return checkResult;
	}


	public Set<ISVNItem> getAccessListing(String locationId)
	{
		SVNLocation location 		= getInfoManager().getLocation(locationId);
		Set<ISVNItem> accessUnitSet 	= new HashSet<ISVNItem>();
		if(null != location)
		{
			for(String accessUnitId : location.getAccessUnits())
			{
				AccessUnit accessUnit = SVNInfoManager.getInfoManager().getAccessUnit(accessUnitId);
				accessUnitSet.add(accessUnit);				
			}
		}

		return accessUnitSet;
	}
}
